import Redis from 'ioredis'
import config from '../config/index.js'
import logger from './logger.js'
import { REDIS_PREFIXES, REDIS_CHANNELS } from '../constants/index.js'

/**
 * Redis 连接管理器
 * 管理命令、发布、订阅三个连接
 */
class RedisManager {
  constructor() {
    function createRedisConnection() {
      if (config.redis.cluster.enable) {
        return new Redis.Cluster(config.redis.cluster.nodes, config.redis.cluster.options)
      } else {
        return new Redis(config.redis)
      }
    }

    this.redisCmd = createRedisConnection()
    this.redisPub = createRedisConnection()
    this.redisSub = createRedisConnection()
    
    this.setupSubscriptions()
  }

  /**
   * 设置 Redis 订阅
   */
  setupSubscriptions() {
    this.redisSub.subscribe(REDIS_CHANNELS.BROADCAST, REDIS_CHANNELS.RELAY, (err) => {
      if (err) {
        logger.error('Redis subscribe error:', err)
      } else {
        logger.info('Redis订阅成功')
      }
    })
  }

  /**
   * 获取命令连接
   */
  getCommandClient() {
    return this.redisCmd
  }

  /**
   * 获取发布连接
   */
  getPublishClient() {
    return this.redisPub
  }

  /**
   * 获取订阅连接
   */
  getSubscribeClient() {
    return this.redisSub
  }

  /**
   * 房间管理相关方法
   */
  async addUserToRoom(roomId, uid, connId) {
    const roomKey = REDIS_PREFIXES.ROOM + roomId
    await this.redisCmd.hset(roomKey, uid, connId)
  }

  async removeUserFromRoom(roomId, uid) {
    const roomKey = REDIS_PREFIXES.ROOM + roomId
    await this.redisCmd.hdel(roomKey, uid)
  }

  async getRoomMembers(roomId) {
    const roomKey = REDIS_PREFIXES.ROOM + roomId
    return await this.redisCmd.hgetall(roomKey)
  }

  async isRoomEmpty(roomId) {
    const roomKey = REDIS_PREFIXES.ROOM + roomId
    const members = await this.redisCmd.hgetall(roomKey)
    return Object.keys(members).length === 0
  }

  async deleteRoom(roomId) {
    const roomKey = REDIS_PREFIXES.ROOM + roomId
    await this.redisCmd.del(roomKey)
  }

  /**
   * 连接管理相关方法
   */
  async setConnectionInfo(connId, roomId, uid) {
    const connKey = REDIS_PREFIXES.CONN + connId
    await this.redisCmd.set(connKey, JSON.stringify({ roomId, uid }))
  }

  async getConnectionInfo(connId) {
    const connKey = REDIS_PREFIXES.CONN + connId
    const info = await this.redisCmd.get(connKey)
    return info ? JSON.parse(info) : null
  }

  async deleteConnectionInfo(connId) {
    const connKey = REDIS_PREFIXES.CONN + connId
    await this.redisCmd.del(connKey)
  }

  /**
   * 通话管理相关方法
   */
  async addUserToCall(roomId, uid, connId) {
    const callKey = REDIS_PREFIXES.CALL + roomId
    await this.redisCmd.hset(callKey, uid, connId)
  }

  async removeUserFromCall(roomId, uid) {
    const callKey = REDIS_PREFIXES.CALL + roomId
    await this.redisCmd.hdel(callKey, uid)
  }

  async getCallMembers(roomId) {
    const callKey = REDIS_PREFIXES.CALL + roomId
    return await this.redisCmd.hgetall(callKey)
  }

  async deleteCall(roomId) {
    const callKey = REDIS_PREFIXES.CALL + roomId
    await this.redisCmd.del(callKey)
  }

  async isInCall(roomId) {
    const callKey = REDIS_PREFIXES.CALL + roomId
    const members = await this.redisCmd.hgetall(callKey)
    return Object.keys(members).length > 0
  }

  /**
   * 设备管理相关方法
   */
  async addDeviceToRoom(roomId, deviceId) {
    const deviceKey = REDIS_PREFIXES.DEVICE + roomId
    await this.redisCmd.sadd(deviceKey, deviceId)
  }

  async removeDeviceFromRoom(roomId, deviceId) {
    const deviceKey = REDIS_PREFIXES.DEVICE + roomId
    await this.redisCmd.srem(deviceKey, deviceId)
  }

  async getRoomDevices(roomId) {
    const deviceKey = REDIS_PREFIXES.DEVICE + roomId
    return await this.redisCmd.smembers(deviceKey)
  }

  /**
   * 消息发布相关方法
   */
  async publishBroadcast(connId, payload) {
    await this.redisPub.publish(REDIS_CHANNELS.BROADCAST, JSON.stringify({
      connId,
      payload
    }))
  }

  async publishRelay(connId, payload) {
    await this.redisPub.publish(REDIS_CHANNELS.RELAY, JSON.stringify({
      connId,
      payload
    }))
  }

  /**
   * 清理相关方法
   */
  async cleanupStaleConnections() {
    const connKeys = await this.redisCmd.keys(REDIS_PREFIXES.CONN + '*')
    const callKeys = await this.redisCmd.keys(REDIS_PREFIXES.CALL + '*')
    
    for (const key of callKeys) {
      await this.redisCmd.del(key)
    }
    for (const key of connKeys) {
      await this.redisCmd.del(key)
    }
  }

  /**
   * 获取所有房间信息
   */
  async getAllRooms() {
    const roomKeys = await this.redisCmd.keys(REDIS_PREFIXES.ROOM + '*')
    const rooms = []
    
    for (const key of roomKeys) {
      const roomId = key.replace(REDIS_PREFIXES.ROOM, '')
      const members = await this.redisCmd.hgetall(key)
      const inCall = await this.isInCall(roomId)
      
      for (const device in members) {
        const connId = members[device]
        const connExists = await this.redisCmd.exists(REDIS_PREFIXES.CONN + connId)
        rooms.push({
          roomId,
          deviceId: device,
          connId: connId || '',
          isOnline: !!connExists,
          status: inCall ? 'active' : 'idle'
        })
      }
    }
    
    return rooms
  }

  /**
   * 获取所有设备信息
   */
  async getAllDevices() {
    const deviceKeys = await this.redisCmd.keys(REDIS_PREFIXES.DEVICE + '*')
    const devices = []
    
    for (const key of deviceKeys) {
      const roomId = key.replace(REDIS_PREFIXES.DEVICE, '')
      const members = await this.redisCmd.smembers(key)
      
      for (const device of members) {
        const connId = await this.redisCmd.hget(REDIS_PREFIXES.ROOM + roomId, device)
        const connExists = await this.redisCmd.exists(REDIS_PREFIXES.CONN + connId)
        devices.push({
          roomId,
          deviceId: device,
          isOnline: !!connExists
        })
      }
    }
    
    return devices
  }
}

// 创建单例实例
const redisManager = new RedisManager()

export default redisManager
